package net.alche.fa.core.doing;

import net.alche.fa.core.FaPlatform;
import net.alche.fa.core.model.Logic;
import net.alche.fa.core.model.FaValue;
import net.alche.al.util.Far;
import net.alche.fa.core.CodeLevel;
import net.alche.fa.core.SageStone;
import net.alche.fa.core.FaException;
import java.util.List;
import java.util.ArrayList;

//
// AbstractDo
//
@SuppressWarnings("all")
public abstract class AbstractDoing {
  FaPlatform plat;

  abstract public boolean matched(String what, Logic g);

  abstract public FaValue doing(Logic g, CodeLevel lvl, SageStone st) throws FaException;

  public FaValue runNext(SageStone st, CodeLevel lvl, List<Logic> logicList) throws FaException {
    return null;
  }

  public FaValue getLogicObjVal(SageStone st, CodeLevel lvl, Logic logic) throws FaException {
    if (logic.getFaObjValue() != null) {
      return logic.getFaObjValue();
    }
    if (logic.getLogicObj() != null) {
      if (logic.getLogicObj().getWhat() == null && logic.getLogicObj().getFaObjValue() != null) {
        return logic.getLogicObj().getFaObjValue();
      } else if (logic.getLogicObj().getWhat() == null && logic.getLogicObj().getObj() != null) {
        return st.getVarData(logic.getLogicObj().getObj(), lvl);
      }
      CodeLevel cl = lvl.instanceDeep();
      cl.logicParam = lvl.logicParam;
      return st.runCode(logic.getLogicObj(), cl).returnObj;
    }
    if (logic.getObj() != null) {
      if ("(".equals(logic.getWhat())) {
        return st.getFaClass().call(logic.obj, this.getFaValueList(st, lvl, logic.param), lvl);
      }
      FaValue back = st.getVarData(logic.getObj(), lvl);
      if (logic.getWhat() != null && (logic.getWhat().equals("++") || logic.getWhat().equals("--"))) {
        return PlusPlusDo.doPlusPlus(logic, back);
      }
      return back;
    }
    return null;
  }

  public FaValue getLogicDataVal(SageStone st, CodeLevel lvl, Logic logic) throws FaException {
    if (logic.getFaDataValue() != null) {
      return logic.getFaDataValue();
    }
    if (logic.getLogicData() != null) {
      if (logic.getLogicData().getWhat() == null && logic.getLogicData().getFaObjValue() != null) {
        return logic.getLogicData().getFaObjValue();
      }
      CodeLevel obj = st.runCode(logic.getLogicData(), lvl.instanceDeep());
      return obj.returnObj;
    }
    if (logic.getData() != null) {
      return st.getVarData(logic.getData(), lvl);
    }
    return null;
  }

  public List<FaValue> getFaValueList(SageStone st, CodeLevel lvl, Logic logic) throws FaException {
    List<FaValue> gicList = new ArrayList<>();
    if (logic.getParam() != null && !logic.getParam().isEmpty()) {
      for (Logic gic : logic.getParam()) {
        FaValue ll = this.getLogicValue(st, lvl, gic);
        gicList.add(ll);
      }
    }
    return gicList;
  }

  public List<FaValue> getFaValueList(SageStone st, CodeLevel lvl, List<Logic> logicList) throws FaException {
    List<FaValue> valList = new ArrayList<>();
    if (logicList != null && !logicList.isEmpty()) {
      for (Logic gic : logicList) {
        FaValue ll = this.getLogicValue(st, lvl, gic);
        valList.add(ll);
      }
    }
    return valList;
  }

  public FaValue getLogicValue(SageStone st, CodeLevel lvl, Logic g) throws FaException {
    FaValue v = null;
    if (g.getWhat() != null) {
      v = st.runCodeValue(g, lvl);
    } else if (g.getFaObjValue() != null) {
      return g.getFaObjValue();
    } else if (g.getWhat() == null) {
      return this.getLogicObjVal(st, lvl, g);
    }
    return v;
  }

  private void getLogicList(SageStone st, CodeLevel lvl, Logic logic, List<FaValue> gicList) throws FaException {
    if (logic == null) {
      return;
    }
    if (logic.getFaObjValue() != null || logic.getObj() != null || logic.getLogicObj() != null) {
      gicList.add(getLogicObjVal(st, lvl, logic));
    }
    if (logic.getLogicData() != null) {
      getLogicList(st, lvl, logic.getLogicData(), gicList);
    }
  }

  // FaValist List转Java-Object数组
  public Object[] parseToJavaArr(List<FaValue> paramList) {
    Object[] params = null;
    FaValue ov = new FaValue();
    if (paramList != null && !paramList.isEmpty()) {
      params = new Object[paramList.size()];
      for (int i = 0; i < paramList.size(); i++) {
        params[i] = paramList.get(i).getValue();
      }
    }
    if (params == null) {
      params = new Object[] {};
    }
    return params;
  }

  public FaPlatform getPlat() {
    return this.plat;
  }

  public void setPlat(FaPlatform plat) {
    this.plat = plat;
  }
}